﻿using NovoSerDes.Funcs;
using Sunny.UI;
using Sunny.UI.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;


namespace NovoSerDes.Forms
{
    public partial class Form_EOM : Form
    {
        SerDesComm commDev;
        public Form_EOM(SerDesComm commDev)
        {
            InitializeComponent();
            this.commDev = commDev;

            this.cmb_ChannelSel.SelectedIndex = 1;
            this.cmb_popThresh.SelectedIndex = 4;
            this.cmb_UICode.SelectedIndex = 0;
            this.comboBox_TxSpeed.SelectedIndex = 1;
            this.comboBox_TxDevAddr.SelectedIndex = 0;

            EOM_UI_Init();

            uiBarChart_DebugDFT.Visible = false;
            uiLineChart_DebugDFT.Visible = true;
        }

        #region Params
        SerDesCH cur_ch = SerDesCH.CH_B;
        int ui_align_tgt_phase = 0;
        int ui_align_last_phase = 0;
        TXSpeed tx_speed = TXSpeed.TX_8G;
        private byte txDevAddr = 0x40;
        bool printFlag = false;

        UInt32 eom_ui_align_fail = 0;
        //UInt32 if_eom_ui_align_fail = 0;

        UInt32 DFE_F0 = 0;
        int UI_CODE = 64;   //12.8/8/6.4Gbps ->64; 4/6.4Gbps -> 256; 2Gbps -> 256
        int[][] eye_diagram = new int[128][];         // storage eye’s Horizontal and vertical coordinates
        long esm_pop_thresh = 10 ^ 4;

        int eye_pass_p_n = 0;

        string logFileName = Environment.CurrentDirectory + "eye_debug.csv";
        #endregion


        #region Funcs
        private bool Update_UI_Code()
        {
            UI_CODE = 64;   //ToDo: change based on speed, need read back speed registers
            return false;
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ns_ew">True: ew; False: ns</param>
        /// <returns></returns>
        private bool EOM_Init(SerDesCH ch)
        {
            bool ret = true;
            int offset = 0;
            int timeout = 1000;     // 1000*5ms = 5Sec

            // 3.1 - 3.2: NS_Base + 0x1000 = EW_Base
            offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            #region (1) Set EOM Registers
            ret &= commDev.IICWrite((UInt32)(0x7484 + offset), 0x01, 17, 21);  //reg_eom_ui_align_pos = 1
            // Speed UP EOM
            ret &= commDev.IICWrite((UInt32)(0x75AC + offset), 0x01, 30, 30);  //reg_g1_real_time_phase_adapt = 1
            // Set esm_pop_thres
            UInt32 tempData = (UInt32)esm_pop_thresh;
            Console.WriteLine("esm_pop_thresh:{0}", esm_pop_thresh);
            ret &= commDev.IICWrite((UInt32)(0x752C + offset), tempData, 0, 31);  //reg_eom_set1_pop_cnt1 for low 32bits
            tempData = (UInt32)(esm_pop_thresh >> 32);
            ret &= commDev.IICWrite((UInt32)(0x7530 + offset), tempData, 0, 31);  //reg_eom_set1_pop_cnt1 for high 32bits

            ret &= commDev.IICWrite((UInt32)(0x7464 + offset), 0x05, 16, 18);     //Set EOM UI Align err_cnt 's max value is 32
            if (!ret)
                return ret;
            #endregion 


            #region (2) Set Other Registers and global variables
            ui_align_tgt_phase = 0;
            ui_align_last_phase = 0;
            if (!ret)
                return ret;
            #endregion

            #region ISOLATION and Speed setting

            //Isolation
            //ret = commDev.IICWrite((UInt32)(0x7000 + offset), 0x26, 24, 31);        //password
            //ret &= commDev.IICWrite((UInt32)(0x7000 + offset), 0x0, 23, 23);        //boardcast clear B23
            //ret &= commDev.IICWrite((UInt32)(0x7008 + offset), 0x01, 6, 6);         //cmn_glu isolation mode
            //ret &= commDev.IICWrite((UInt32)(0x74C4 + offset), 0x01, 14, 14);       //dfe isolation mode

            ////Speed Setting
            //ret = commDev.IICWrite((UInt32)(0x759C + offset), 0x2, 21, 23);         //sel_bits
            //ret &= commDev.IICWrite((UInt32)(0x759C + offset), 0x4, 17, 20);        //phy_gen_rx   data_rate 0x0/0x2/0x4/0x5 2g/4g/8g/12.8g
            //ret &= commDev.IICWrite((UInt32)(0x759C + offset), 0x0, 13, 16);        //phy_gen_tx
            //ret &= commDev.IICWrite((UInt32)(0x76A4 + offset), 0x04, 4, 6);         //phy_mode
            //ret &= commDev.IICWrite((UInt32)(0x76A8 + offset), 0x1, 20, 20);        //pu_ivref

            //ret &= commDev.IICWrite((UInt32)(0x75EC + offset), 0x1, 10, 10);        //reg_pll_rate_sel_dis = 1
            //if (!ret)
            //    return ret;
            #endregion 

            #region (3) - Save F0
            ret = commDev.IICRead((UInt32)(0x741C + offset), out DFE_F0, 17, 22);  //Read reg_rd_dfe_f0[5:0]
            if (!ret)
                return ret;
            #endregion
            
            #region (9) - Enable Eye Monitor
            Thread.Sleep(1);        // delay 10000ns, actually delayed 1ms
            ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x1, 10, 10);        //reg_eom_en = 1
            UInt32 eom_ready = 0;
            timeout = 1000;          // 1000*5ms = 5Sec
            while (--timeout > 0)
            {
                ret &= commDev.IICRead((UInt32)(0x7418 + offset), out eom_ready, 31, 31);  //Read reg_rd_dfe_f0[5:0])
                if (!ret)
                    return ret;
                else if (eom_ready == 1)
                    break;

                Thread.Sleep(5);
            }

            if (timeout == 0)
                return false;
            #endregion

            #region (10) - set esm voltage
            int ems_vol = 0; //ToDo, verify voltage value
            ret = EOM_Set_ESM_Voltage(ems_vol, ch);
           #endregion

            return ret;
        }

        private bool EOM_Alignment(SerDesCH ch)
        {
            bool ret = false;

            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            #region (11) Execute EOM Align Calibration
            UInt32 align_eom_done = 0;
            ret = commDev.IICRead((UInt32)(0x7574 + offset), out align_eom_done, 2, 2);
            Console.WriteLine("align_eom_done:{0}", align_eom_done);
            ret = commDev.IICWrite((UInt32)(0x7590 + offset), 0x1, 4, 4);        //reg_align_eom_start = 1
            Thread.Sleep(5);
            ret &= commDev.IICWrite((UInt32)(0x7590 + offset), 0x0, 4, 4);        //reg_align_eom_start = 0
            if (!ret)
                return ret;
            // wait reg_rd_align_eom_done = 0
            int timeout = 1000;     //1000*5ms = 5Sec
            do
            {
                ret = commDev.IICRead((UInt32)(0x7574 + offset), out align_eom_done, 2, 2);
                if (!ret)
                    return ret;

                Thread.Sleep(5);
            } while ((--timeout > 0) && (align_eom_done == 0));
            if (align_eom_done == 0)
            {
                Console.WriteLine("align_eom_done should be 1, readback is 0");
                return false;
            }

            //ret = commDev.IICWrite((UInt32)(0x7590 + offset), 0x0, 4, 4);       //reg_align_eom_start = 0
            ////ret &= commDev.IICWrite((UInt32)(0x7574 + offset), 0x1, 2, 2);       //reg_rd_align_eom_done = 1
            //if (!ret)
            //    return ret;

            // wait reg_rd_align_eom_done = 1            
            //timeout = 1000;     //1000*5ms = 5Sec
            //do
            //{ 
            //    ret = commDev.IICRead((UInt32)(0x7574 + offset), out align_eom_done, 2, 2);
            //    if(!ret)
            //        return ret;

            //    Thread.Sleep(5);
            //} while ((--timeout > 0) && (align_eom_done == 0));

            //if(align_eom_done == 0)
            //    return false;
            #endregion

            #region (12) Clear DFE Done ISR
            ret = commDev.IICWrite((UInt32)(0x7464 + offset), 0x1, 2, 2);        //reg_dfe_done_int_clear = 1
            ret &= commDev.IICWrite((UInt32)(0x7464 + offset), 0x0, 2, 2);        //reg_dfe_done_int_clear = 0
            if (!ret)
                return ret;
            #endregion

            #region (13) Loop execute eom_ui_align
            int maxLoopTimes = 20;
            for (int ix = 0; ix < maxLoopTimes; ix++)
            {
                int ui_align_ret = EOM_UI_Align(ch);
                if (ui_align_ret == -1)
                    return false;
                else if (ui_align_ret == 0)
                    break;
            }

            ret = commDev.IICRead((UInt32)(0x7420 + offset), out eom_ui_align_fail, 2, 2);  //Read reg_rd_eom_ui_align_fail;  
            if (!ret)
                return ret;

            if (eom_ui_align_fail != 0)
                return false;
            #endregion

            return ret;
        }
        
        private int EOM_UI_Align(SerDesCH ch)
        {
            bool ret = false;
            
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            #region //(1) Read Calibration Results and             
            ret = commDev.IICRead((UInt32)(0x7574 + offset), out cal_eom_ph, 4, 10);  //Read reg_rd_dfe_f0[5:0]
            if (!ret)
                return -1;
            #endregion

            #region //(2) EOM UI Align Start
            ret = commDev.IICWrite((UInt32)(0x7484 + offset), 0x01, 16, 16);  //reg_eom_ui_align_start_bits = 1
            ret &= commDev.IICWrite((UInt32)(0x7484 + offset), 0x0, 16, 16);  //reg_eom_ui_align_start_bits = 0
            if (!ret)
                return -1;
            #endregion

            #region //(3) Read dfe_done_int
            UInt32 if_dfe_done = 0;
            int timeout = 1000; // 1000*5ms = 5Sec
            do
            {
                ret = commDev.IICRead((UInt32)(0x741C + offset), out if_dfe_done, 23, 23);  //Read reg_rd_dfe_done_int
                if (!ret)
                    return -1;

                Thread.Sleep(5);
            }
            while ((if_dfe_done == 0) && (--timeout > 0));

            //Console.WriteLine("dfe wait done timeout:{0}", timeout);
            if (timeout == 0)
                return -1;
            #endregion

            #region // (4) Clear dfe_done ISR
            ret = commDev.IICWrite((UInt32)(0x7464 + offset), 0x01, 2, 2);  //reg_dfe_done_int_clear = 1
            ret &= commDev.IICWrite((UInt32)(0x7464 + offset), 0x0, 2, 2);  //reg_dfe_done_int_clear = 0
            if (!ret)
                return -1;            
            #endregion

            #region (5) Wait utill eom ui align done
            UInt32 if_eom_ui_align_done = 0;
            timeout = 1000; // 1000*5ms = 5Sec
            do
            {
                ret = commDev.IICRead((UInt32)(0x7420 + offset), out if_eom_ui_align_done, 3, 3);  //Read reg_rd_eom_ui_align_done
                if (!ret)
                    return -1;

                Thread.Sleep(5);
            }
            while ((if_eom_ui_align_done == 0) && (--timeout > 0));
            Console.WriteLine("wait eom_ui_align_done timeout:{0}", timeout);
            if(timeout == 0) return -1;
            
            ret = commDev.IICRead((UInt32)(0x7420 + offset), out eom_ui_align_fail, 2, 2);  //Read reg_rd_eom_ui_align_fail
            if (!ret)
                return -1;
            #endregion

            #region (6) Loop execute eom_ui_align_set_phase(pi)
            int step_ui_align = 2;
            if (eom_ui_align_fail == 1)
            {
                for (int pi = 0; pi <= UI_CODE; pi += step_ui_align)
                {
                    ui_align_tgt_phase = pi + ui_align_last_phase;
                    if (EOM_UI_Align_Set_Phase(ui_align_tgt_phase % 128, ch) == false)
                        return -1;
                }
                ui_align_last_phase = ui_align_tgt_phase;
                return 1;
            }
            else
            {
                Console.WriteLine("UI Align Success!");
                ui_align_last_phase = ui_align_tgt_phase;
                return 0;
                //indey = 20;  //Break for loop		
            }
            #endregion
        }

        UInt32 cal_eom_ph = 0;
        int esm_phase = 0;
        int esm_voltage = 0;
        int cur_phase = 0;
        int eye_vp = 64;              //Top side maxvoltage initial value
        int eye_vn = 64;              //Bottom side minvoltage initial value
        int esm_v_step = 1;           // esm voltagesweep step size
        int esm_p_step = 1;           // esm phase sweepstep size
        int eye_hc = 64;
        int eye_vc = 64;
        int eye_hl = 0;
        int eye_hr = 0;
        private bool EOM_Print(SerDesCH ch)
        {
            bool ret = false;
            int timeout = 1000;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            #region EOM Sweep Initialization
            //int esm_phase = 0;
            //int esm_voltage = 0;
            //int eye_vp = 64;              //Top side maxvoltage initial value
            //int eye_vn = 64;              //Bottom side minvoltage initial value
            //int esm_v_step = 1;           // esm voltagesweep step size
            //int esm_p_step = 1;           // esm phase sweepstep size
            //int eye_hc = 64;
            //int eye_vc = 64;
            //int eye_hl = 0;
            //int eye_hr = 0;

            esm_phase = 0;
            esm_voltage = 0;
            eye_vp = 64;
            eye_vn = 64;

            if (eye_diagram[0] == null)
            {
                for (int ix = 0; ix < 128; ix++)
                    eye_diagram[ix] = new int[128];
            }
            #endregion 

            #region (15) Count Rising Edge (Upper Half Eye)
            ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x1, 30, 31);        //reg_pattern = 2’b01
            //ret = commDev.IICWrite((UInt32)(0x7528 + offset), (UInt32)this.cmb_Pattern_upper.SelectedIndex, 30, 31);        //reg_pattern = 2’b01
            if (!ret)
                return ret;
            #endregion 

            #region (16) DFE F0 Polarity 
            ret = commDev.IICWrite((UInt32)(0x753C + offset), 0x1, 17, 18);       //reg_eom_set1_eom_state = 2’b01
            //ret = commDev.IICWrite((UInt32)(0x753C + offset), (UInt32)this.cmb_F0Polarity_upper.SelectedIndex, 17, 18);       //reg_eom_set1_eom_state = 2’b01
            if (!ret)
                return ret;
            #endregion 

            #region (17) Read Calibration Results And Save
            ret = commDev.IICRead((UInt32)(0x7574 + offset), out cal_eom_ph, 4, 10);  //Read reg_rd_cal_eom_ph_rd_bits[6:0]	
            if (!ret)
                return ret;
            else
                Console.WriteLine("Cal_eom_ph:{0}(0x{1})", cal_eom_ph, cal_eom_ph.ToString("X"));

            //Set global variable: cur_phase
            cur_phase = ui_align_tgt_phase % 128;
            Console.WriteLine("Cur_phase:{0}, ui_align_tgt_phase:{1}", cur_phase, ui_align_tgt_phase);

            ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x0, 25, 30);          //Turn Off dfe_update_en
            if (!ret)
                return ret;
            #endregion

            #region (18) set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            else
                Console.WriteLine("EOM_Set_ESM_Phase:{0}", 0);

            #endregion

            #region (19) Sweep Phase from center to right and Voltage from center to top
            Console.WriteLine("Start sweeping phase: center -> right and voltage: center -> top");
            ret = EOM_Sweep_Phase(false, true, ch);
            if (!ret)
                return false;
            //for (esm_phase = 0; esm_phase < 61; esm_phase += esm_p_step)
            //{
            //    if(!EOM_Set_ESM_Phase(esm_phase, ch))
            //        return false; 

            //    for (esm_voltage = 0; esm_voltage < 61; esm_voltage += esm_v_step)
            //    {
            //        if(!EOM_Set_ESM_Voltage(esm_voltage, ch))
            //            return false;

            //        ret = EOM_Check_Eye(esm_phase, esm_voltage, true, ch);
            //        if (!ret)
            //            return ret;

            //        if ((eye_vp < (eye_vc + esm_voltage)) && (eye_pass_p_n == 1))
            //            eye_vp = eye_vc + esm_voltage;
            //        if ((eye_vn > (eye_vc - esm_voltage)) && (eye_pass_n == 1))
            //            eye_vn = eye_vc - esm_voltage;
            //        if ((eye_pass_p_n == 0) && (eye_pass_n == 0))
            //            break;
            //    }
            //}

            #endregion

            #region (20) set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion

            #region (21) Sweep Phase from center to left and Voltage from center to top
            Console.WriteLine("Start sweeping phase: center -> left and voltage: center -> top");
            ret = EOM_Sweep_Phase(true, true, ch);
            if (!ret)
                return false;
            #endregion 

            #region (22) Execute set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion 

            #region (23) Find Boundary
            //while (eye_vp < 127)
            //{
            //    eye_vp++;
            //}
            //while (eye_vn > 0)
            //{
            //    eye_vn--;
            //}

            #endregion 


            #region (24) Execute plot_eye
            //EOM_Plot_Eye();
            #endregion

            #region (25) EOM Sweep Initialization
            esm_phase = 0;
            esm_voltage = 0;
            eye_vp = 64;
            eye_vn = 64;

            #endregion 

            #region (26) Count Rising Edge (Lower Half Eye)
            ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x1, 30, 31);       //reg_pattern = 2 'b10
            //ret = commDev.IICWrite((UInt32)(0x7528 + offset), (UInt32)this.cmb_Pattern_lower.SelectedIndex, 30, 31);       //reg_pattern = 2 'b10
            if (!ret)
                return ret;
            #endregion 

            #region (27) DFE F0 Polarity
            ret = commDev.IICWrite((UInt32)(0x753C + offset), 0x01, 17, 18);       //reg_eom_set1_eom_state = 2 'b00
            //ret = commDev.IICWrite((UInt32)(0x753C + offset), (UInt32)this.cmb_F0Polarity_lower.SelectedIndex, 17, 18);       //reg_eom_set1_eom_state = 2 'b00
            if (!ret)
                return ret;
            #endregion 

            #region (28) Read Calibration Results And Save
            cal_eom_ph = 0;
            ret = commDev.IICRead((UInt32)(0x7574 + offset), out cal_eom_ph, 4, 10);  //Read reg_rd_cal_eom_ph_rd_bits[6:0]	
            Console.WriteLine("cal_eom_ph = {0}", cal_eom_ph);
            if (!ret)
                return ret;

            //Set global variable: cur_phase
            cur_phase = ui_align_tgt_phase % 128;
            Console.WriteLine("Cur_phase:{0}, ui_align_tgt_phase:{1}", cur_phase, ui_align_tgt_phase);

            //ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x0, 25, 30);          //Turn Off dfe_update_en
            //if (!ret)
            //    return ret;
            #endregion 

            #region (29) Execute set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion 

            #region (30) Sweep Phase from center to right and Voltage from center to bottom
            Console.WriteLine("Start sweeping phase: center -> right and voltage: center -> bottom");
            ret = EOM_Sweep_Phase(false, false, ch);            
            if (!ret)
                return false;
            #endregion 

            #region (31) Execute set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion

            #region (32) Sweep Phase from center to left and Voltage from center to bottom
            Console.WriteLine("Start sweeping phase: center -> left and voltage: center -> bottom"); 
            ret = EOM_Sweep_Phase(true, false, ch);            
            if (!ret)
                return false;
            #endregion

            #region (33) Execute set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion

            #region (34) Find Boundary
            //while (eye_vp < 127)
            //{
            //    eye_vp++;
            //}
            //while (eye_vn > 0)
            //{
            //    eye_vn--;
            //}

            #endregion

            #region (35) Execute plot_eye
            //EOM_Plot_Eye();
            #endregion

           

            return ret;
        }

       
        private bool EOM_Print_New(SerDesCH ch)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            #region EOM Sweep Initialization
            //int esm_phase = 0;
            //int esm_voltage = 0;
            //int eye_vp = 64;              //Top side maxvoltage initial value
            //int eye_vn = 64;              //Bottom side minvoltage initial value
            //int esm_v_step = 1;           // esm voltagesweep step size
            //int esm_p_step = 1;           // esm phase sweepstep size
            //int eye_hc = 64;
            //int eye_vc = 64;
            //int eye_hl = 0;
            //int eye_hr = 0;

            uiProcessBar_EOM.Value = 0;
            uiProcessBar_EOM.Update();

            if (eye_diagram[0] == null)
            {
                for (int ix = 0; ix < 128; ix++)
                    eye_diagram[ix] = new int[128];
            }
            #endregion 

            //0: top_right; 1: top_left; 2: bottom_right; 3: bottom_left
            UInt32 reg_pattern = 0;
            UInt32 reg_polarity = 0;
            //for (int zone_ix = 3; zone_ix >= 0; zone_ix--)
            for (int zone_ix = 0; zone_ix < 4; zone_ix++)
            {
                esm_phase = 0;
                esm_voltage = 0;
                eye_vp = 64;
                eye_vn = 64;

                switch (zone_ix)
                {
                    case 0:
                        reg_pattern = 2;
                        reg_polarity = 2;
                        break;
                    case 1:
                        reg_pattern = 1;
                        reg_polarity = 1;
                        break;
                    case 2:
                        reg_pattern = 1;
                        reg_polarity = 1;
                        break;
                    case 3:
                        reg_pattern = 2;
                        reg_polarity = 2;
                        break;
                    default:
                        return false;
                }

                #region (15) Count Rising/Falling Edge
                //ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x1, 30, 31);        //reg_pattern = 2’b01
                ret = commDev.IICWrite((UInt32)(0x7528 + offset), reg_pattern, 30, 31);   //reg_pattern
                if (!ret)
                    return ret;
                #endregion

                #region (16) DFE F0/F1 Polarity 
                //ret = commDev.IICWrite((UInt32)(0x753C + offset), 0x1, 17, 18);          //reg_eom_set1_eom_state
                ret = commDev.IICWrite((UInt32)(0x753C + offset), reg_polarity, 17, 18);   //reg_eom_set1_eom_state
                if (!ret)
                    return ret;
                #endregion

                #region (17) Read Calibration Results And Save
                ret = commDev.IICRead((UInt32)(0x7574 + offset), out cal_eom_ph, 4, 10);  //Read reg_rd_cal_eom_ph_rd_bits[6:0]	
                if (!ret)
                    return ret;
                else
                    Console.WriteLine("Cal_eom_ph:{0}(0x{1})", cal_eom_ph, cal_eom_ph.ToString("X"));

                //Set global variable: cur_phase
                cur_phase = ui_align_tgt_phase % 128;
                Console.WriteLine("Cur_phase:{0}, ui_align_tgt_phase:{1}", cur_phase, ui_align_tgt_phase);

                ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x0, 25, 30);          //Turn Off dfe_update_en
                if (!ret)
                    return ret;
                #endregion

                #region (18) set_esm_phase(0)
                if (!EOM_Set_ESM_Phase(0, ch))
                    return false;
                else
                    Console.WriteLine("EOM_Set_ESM_Phase:{0}", 0);

                #endregion

                #region (19) Sweep Phase from center to right and Voltage from center to top
                //Console.WriteLine("Start sweeping phase: center -> right and voltage: center -> top");
                switch (zone_ix)
                {
                    case 0:
                        Console.WriteLine("Start sweeping phase: center -> right and voltage: center -> top");
                        break;
                    case 1:
                        Console.WriteLine("Start sweeping phase: center -> left and voltage: center -> top");
                        break;
                    case 2:
                        Console.WriteLine("Start sweeping phase: center -> right and voltage: center -> bottom");
                        break;
                    case 3:
                        Console.WriteLine("Start sweeping phase: center -> left and voltage: center -> bottom");
                        break;
                    default:
                        return false;
                }
                bool if_top = zone_ix < 2 ? true : false;
                bool if_left;
                if(zone_ix == 0 || zone_ix == 2)
                {
                    if_left = false;
                }
                else if (zone_ix == 1 || zone_ix == 3)
                {
                    if_left = true;
                }
                else
                {
                    if_left = false;
                    Console.WriteLine("zone_ix Error");
                }
                ret = EOM_Sweep_Phase(if_left, if_top, ch);
                if (!ret)
                    return false;

                #endregion

                #region (20) set_esm_phase(0)
                if (!EOM_Set_ESM_Phase(0, ch))
                    return false;
                #endregion

            }

            return ret;
        }

        private bool EOM_Turn_Off(SerDesCH ch)
        {
            bool ret = false;
            int timeout = 1000;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            #region 3.8 EOM Exit
            ret = commDev.IICWrite((UInt32)(0x7468 + offset), DFE_F0, 16, 21);    //reg_dfe_f0_ext = dfe_f0;
            ret &= commDev.IICWrite((UInt32)(0x7470 + offset), 0x1, 26, 31);       //reg_dfe_fx_force = 1
            ret &= commDev.IICWrite((UInt32)(0x7470 + offset), 0x0, 26, 31);       //reg_dfe_fx_force = 0
            if (!ret)
                return ret;
            #endregion

            #region 3.9 Turn Off EOMc
            ret = commDev.IICWrite((UInt32)(0x7484 + offset), 0x0, 17, 21);       //reg_eom_ui_align_pos = 0;
            ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x0, 10, 10);       //reg_eom_en = 0;
            if (!ret)
                return ret;

            UInt32 eom_ready = 0;
            timeout = 1000;          // 1000*5ms = 5Sec
            while (--timeout > 0)
            {
                ret &= commDev.IICRead((UInt32)(0x7418 + offset), out eom_ready, 31, 31);  //Read reg_rd_dfe_f0[5:0])
                if (!ret)
                    return ret;
                else if (eom_ready == 0)
                    break;

                Thread.Sleep(5);
            }
            if (timeout == 0)
                return false;
            #endregion 


            return ret;
        }

        private bool EOM_Set_ESM_Voltage(int voltage, SerDesCH ch)
        {
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;
            bool ret = false;

            if (voltage >= Math.Pow(2, 6))
                return false;

            //Console.WriteLine("Set ESM Voltage:{0}", voltage);
            ret = commDev.IICWrite((UInt32)(0x753C + offset), (UInt32)voltage, 26, 31); //reg_eom_set1_voltage_bits = v[5:0]
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 1, 29, 29);             //reg_eom_set1_v ld_bits = 1
            //ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 1, 27, 28);             //reg_eom_set1_stop_en_bits = 2 'b01 
            //ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0, 29, 29);             //reg_eom_set1_v ld_bits = 0
            //ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0, 27, 28);             //reg_eom_set1_stop_en_bits = 2 'b00

            return ret;
        }

        private bool EOM_UI_Align_Set_Phase(int phase, SerDesCH ch)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            ret = commDev.IICWrite((UInt32)(0x753C + offset), (UInt32)phase, 19, 25);  //reg_eom_set1_phase = phase
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x01, 29, 29);       //reg_eom_set1_vld = 1
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x01, 27, 28);       //reg_eom_set1_stop_en = 2’b01	
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x0, 29, 29);       //reg_eom_set1_vld = 0
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x0, 27, 28);       //reg_eom_set1_stop_en = 2’b00

            return ret;
        }

        private bool EOM_Set_ESM_Phase(int phase, SerDesCH ch)
        {
            bool ret = true;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            //int cur_phase = 0;
            int target_phase = 0;
            int step = 1;
            target_phase = (ui_align_tgt_phase % 128) + phase;
            if (cur_phase <= target_phase)
            {
                while ((target_phase - cur_phase) >= step)
                {
                    cur_phase += step;
                    if (!EOM_Set_EOM_Phase(cur_phase, ch))
                        return false;
                }
            }
            else
            {
                while ((cur_phase - target_phase) > step)
                {
                    cur_phase -= step;
                    if (!EOM_Set_EOM_Phase(cur_phase, ch))
                        return false;
                }
                cur_phase = target_phase;
                if (!EOM_Set_EOM_Phase(cur_phase, ch))
                    return false;
            }

            return ret;
        }

        private bool EOM_Check_Eye(int phase, int voltage, bool if_top, SerDesCH ch)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            long pop_p_n;
            long err_p_n;
            float ber_p_n;
            int x, y;

            pop_p_n = 0;
            err_p_n = 0;

            ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x1, 29, 29);       //reg_eom_set1_vld = 1
            if (!ret)
                return ret;

            Thread.Sleep(1);        //delay 200ns; wait EOM state machine enter SET1 state

            do
            {
                UInt32 tempData = 0;
                ret = commDev.IICRead((UInt32)(0x76A0 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_sample_cnt[31:0];	
                pop_p_n = (long)tempData;
                ret &= commDev.IICRead((UInt32)(0x76A4 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_sample_cnt[63:32];
                pop_p_n += tempData << 32;
                if (!ret)
                    return ret;

                ret = commDev.IICRead((UInt32)(0x7694 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_error_cnt[31:0];	
                err_p_n = (long)tempData;
                ret &= commDev.IICRead((UInt32)(0x7698 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_error_cnt[63:32];
                err_p_n += tempData << 32;
                if (!ret)
                    return ret;

                //Console.WriteLine("popp:{0}, errp:{1}", pop_p_n, err_p_n);
                //pop_p_n = reg_rd_eom_set1_sample_cnt[63:0];
                //err_p_n = reg_rd_eom_set1_error_cnt[63:0];
            } while (pop_p_n < esm_pop_thresh);

            if (pop_p_n == 0)
                return false;

            ber_p_n = err_p_n / pop_p_n;

            x = 64 + phase;
            y = if_top ? 64 + voltage : 64 - voltage;

            if (err_p_n >= 1) 
                eye_diagram[x][y] += 1;
            //else 
            //    eye_diagram[x][y] = 0;

            if (err_p_n < 1) 
                eye_pass_p_n = 1;
            else 
                eye_pass_p_n = 0;

            do
            {
                UInt32 tempData = 0;
                ret = commDev.IICRead((UInt32)(0x76A0 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_sample_cnt[31:0];	
                pop_p_n = (long)tempData;
                ret &= commDev.IICRead((UInt32)(0x76A4 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_sample_cnt[63:32];
                pop_p_n += tempData << 32;
                if (!ret)
                    return ret;
                Thread.Sleep(1);
            } while (pop_p_n < esm_pop_thresh);

            UInt32 eom_set1_rdy = 0;
            ret = commDev.IICRead((UInt32)(0x769C + offset), out eom_set1_rdy, 31, 31);      //Read reg_rd_eom_set1_rdy;
            if (!ret)
                return false;

            if (eom_set1_rdy == 1)
                ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x0, 29, 29);             //reg_eom_set1_vld = 0;
            else
                ret = false;

            return ret;
        }

        private bool EOM_Sweep_Phase(bool if_left, bool if_top, SerDesCH ch)
        {
            bool ret = true;

            if (if_left)    // Center to left
            {
                int count = 0;
                for (esm_phase = -1; esm_phase > -32; esm_phase -= esm_p_step)
                {
                    ret = EOM_Set_ESM_Phase(esm_phase, ch);
                    if (!ret)
                        return false;

                    for (esm_voltage = 0; esm_voltage < 64; esm_voltage += esm_v_step)
                    {
                        if (esm_voltage == 0 && if_top == false) //避免对esm_voltage的重复赋值
                        {
                            continue;
                        }
                        if (!EOM_Set_ESM_Voltage(esm_voltage, ch))
                            return false;
                        if (!EOM_Check_Eye(esm_phase, esm_voltage, if_top, ch))
                        {
                            Console.WriteLine("Check eye failed! if_left:{0}, if_top:{1}, esm_phase = {2}, esm_vol = {3}",
                                if_left, if_top, esm_phase, esm_voltage);
                            return false;
                        }

                        if ((eye_vp < (eye_vc + esm_voltage)) && (eye_pass_p_n == 1))
                            eye_vp = eye_vc + esm_voltage;
                            //eye_vp = if_top ? eye_vc + esm_voltage : eye_vc - esm_voltage;

                        //eye_vp = eye_vc + esm_voltage;
                        if ((eye_vn > (eye_vc - esm_voltage)) && (eye_pass_p_n == 1))
                            eye_vn = eye_vc - esm_voltage;

                        if (eye_pass_p_n == 0)
                        {
                            count++;
                            if(count == 5)
                            {
                                uiProcessBar_EOM.Value += 4;
                                uiProcessBar_EOM.Update();
                                count = 0;
                            }else if (esm_phase == -31)
                            {
                                uiProcessBar_EOM.Value += 1;
                                uiProcessBar_EOM.Update();
                            }

                            if (printFlag)
                                Console.WriteLine("Exist sweep: esm_phase = {0}, esm_vol = {1}", esm_phase, esm_voltage);
                            break;
                        }
                    }
                    //if (esm_voltage == 0)   //ToDo: 这条命令执行不到
                    //{
                    //    eye_hl = eye_hc + esm_phase;
                    //    break;
                    //}
                }
            }
            else       // Center to right
            {
                int count = 0;
                for (esm_phase = 0; esm_phase < 32; esm_phase += esm_p_step)
                {
                    ret = EOM_Set_ESM_Phase(esm_phase, ch);
                    if (!ret)
                        return false;
                    //else
                    //    Console.WriteLine("Set ESM Phase: {0}", esm_phase);

                    for (esm_voltage = 0; esm_voltage < 64; esm_voltage += esm_v_step)
                    {
                        if (esm_voltage == 0 && if_top == false) //避免对esm_voltage的重复赋值
                        {
                            continue;
                        }
                        if (!EOM_Set_ESM_Voltage(esm_voltage, ch))
                            return false;
                        if (!EOM_Check_Eye(esm_phase, esm_voltage, if_top, ch))
                            return false;

                        if ((eye_vp < (eye_vc + esm_voltage)) && (eye_pass_p_n == 1))
                            eye_vp = eye_vc + esm_voltage;
                            //eye_vp = if_top ? eye_vc + esm_voltage : eye_vc - esm_voltage;
                        if ((eye_vn > (eye_vc - esm_voltage)) && (eye_pass_p_n == 1))
                            eye_vn = eye_vc - esm_voltage;
                        if (eye_pass_p_n == 0)
                        {
                            count++;
                            if (count == 5)
                            {
                                uiProcessBar_EOM.Value += 4;
                                uiProcessBar_EOM.Update();
                                count = 0;
                            }
                            else if (esm_phase == 31)
                            {
                                uiProcessBar_EOM.Value += 1;
                                uiProcessBar_EOM.Update();
                            }

                            if (printFlag)
                                Console.WriteLine("Exist sweep: esm_phase = {0}, esm_vol = {1}", esm_phase, esm_voltage);
                            break;
                        }
                    }
                }
            }


            return ret;
        }

        private bool EOM_Set_EOM_Phase(int phase, SerDesCH ch)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            if (phase >= Math.Pow(2, 7))
                return false;

            if (printFlag)
            {
                Console.WriteLine("Set EOM Phase:{0}", phase);
            }

            ret = commDev.IICWrite((UInt32)(0x753C + offset), (UInt32)phase, 19, 25);  //reg_eom_set1_phase[6:0] = cur_phase[6:0]
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x01, 29, 29);          //reg_eom_set1_v ld = 1
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x01, 27, 28);          //reg_eom_set1_stop_en = 2’b01	
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x00, 29, 29);          //reg_eom_set1_v ld = 0
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x00, 27, 28);          //reg_eom_set1_stop_en = 2’b00
            if (!ret)
                return ret;

            return ret;
        }

        private void EOM_Plot_Eye()
        {
            int x;
            int y;

            if (printFlag)
            {
                Console.WriteLine("*****************************************\n");
                Console.WriteLine("************EYE DIAGRAM BEGIN************\n");
                Console.WriteLine("*****************************************\n");
                for (int ix_vol = 127; ix_vol >= 0; ix_vol--)
                {
                    Console.WriteLine();
                    for (int ix_phase = 0; ix_phase < 128; ix_phase++)
                        Console.Write("{0}", eye_diagram[ix_phase][ix_vol] == 1 ? "1" : " ");
                }

                Console.WriteLine();
            }


            EOM_EyeChar_Refresh();
            btn_ClearEye_Click(null, null);
            //PrintToCSV(eye_diagram, logFileName);

            //for (y = eye_vp; y >= eye_vn; y--)
            //{
            //    Console.WriteLine("<%3d>", y);
            //    if (y == 0)
            //    {
            //        Console.WriteLine(" ");
            //        break;
            //    }
            //    for (x = 29; x <= 99; x++)
            //    {
            //        if (eye_diagram[x][y] == 1) Console.WriteLine(" ");
            //        else Console.WriteLine("%b", eye_diagram[x][y]);
            //    } // x
            //    Console.WriteLine(" ");
            //} // y

            if (printFlag)
            {
                Console.WriteLine("*****************************************\n");
                Console.WriteLine("************EYE DIAGRAM END**************\n");
                Console.WriteLine("*****************************************\n");
            }

        }

        private void EOM_EyeChar_Refresh()
        {
            UILineOption option = new UILineOption();
            option.ToolTip.Visible = true;
            option.Title = new UITitle();
            option.Title.Text = "EOM";
            option.Title.SubText = "";

            option.XAxis.Name = "Phase";
            option.YAxis.Name = "Voltage(mV)";
            option.XAxis.SetRange(0, 127);
            //option.YAxis.SetRange(0, 127);
            var series = option.AddSeries(new UILineSeries("Line1"));
            series.Symbol = UILinePointSymbol.Diamond;
            series.SymbolSize = 1;
            series.SymbolLineWidth = 1;
            series.SymbolColor = Color.YellowGreen;
            series.ShowLine = false;

            var series2 = option.AddSeries(new UILineSeries("Line2"));
            series2.Symbol = UILinePointSymbol.Circle;
            series2.SymbolSize = 1;
            series2.SymbolLineWidth = 1;
            series2.SymbolColor = Color.Red;
            series2.ShowLine = false;

            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (cur_ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            UInt32 dfe_lock = 0;
            ret = commDev.IICRead((UInt32)(0x7420 + offset), out dfe_lock, 15, 15);  //reg_rd_dfe_lock;
            if (!ret && dfe_lock != 1)
            {
                Console.WriteLine("dfe_lock Read Error");
                return;
            }

            UInt32 adapted_dfe_res = 0;
            ret = commDev.IICRead((UInt32)(0x7418 + offset), out adapted_dfe_res, 28, 30);  //reg_rd_adapted_dfe_res[2:0];
            if (!ret)
            {
                Console.WriteLine("adapted_dfe_res[2:0] Read Error");
                return;
            }
            double dfe_coef = 1;
            switch (adapted_dfe_res)
            {
                case 0b000:
                    dfe_coef = 1.5; break;
                case 0b001:
                    dfe_coef = 2; break;
                case 0b010:
                    dfe_coef = 2.5; break;
                case 0b011:
                    dfe_coef = 3; break;
                case 0b100:
                    dfe_coef = 3.5; break;
                case 0b101:
                    dfe_coef = 4; break;
                case 0b110:
                    dfe_coef = 4.5; break;
                default:
                    dfe_coef = 2; break;
            }
            Console.WriteLine("dfe_coef:{0}", dfe_coef);

            option.YAxis.SetRange(0, 127 * dfe_coef);

            for (int ix_vol = 127; ix_vol >= 0; ix_vol--)
            {
                for (int ix_phase = 0; ix_phase < 128; ix_phase++)
                //Console.Write("{0}", eye_diagram[ix_phase][ix_vol] == 1 ? "1" : " ");
                {
                    if (eye_diagram[ix_phase][ix_vol] == 1)
                    {
                        series.Add(ix_phase, ix_vol * dfe_coef);
                        //series.A
                    }
                    else if(eye_diagram[ix_phase][ix_vol] > 1) //TODO:当累加到一定数值，点的颜色不同
                    {
                        series2.Add(ix_phase, ix_vol * dfe_coef);
                    }

                }
            }

            

            //option.YAxisScaleLines.Add(new UIScaleLine() { Color = Color.Red, Name = "上限", Value = 3.5 });
            //option.Y2AxisScaleLines.Add(new UIScaleLine() { Color = Color.Gold, Name = "下限", Value = 12, DashDot = true });

            //option.XAxisScaleLines.Add(new UIScaleLine() { Color = Color.Lime, Name = "3", Value = 3 });
            //option.XAxisScaleLines.Add(new UIScaleLine() { Color = Color.Gold, Name = "6", Value = 6 });

            lineChart_EOM.SetOption(option);

            Console.WriteLine("Refresh EOM UI Done");
        }

        private void EOM_UI_Init()
        {
            UILineOption option = new UILineOption();
            option.ToolTip.Visible = true;
            option.Title = new UITitle();
            option.Title.Text = "EOM";
            option.Title.SubText = "";

            //var series = option.AddSeries(new UILineSeries("Line1"));
            ////series.Add(0, 1.2);
            ////series.Add(1, 2.2);
            ////series.Add(2, 3.2);
            ////series.Add(3, 4.2);
            ////series.Add(4, 3.2);
            ////series.Add(5, 2.2);
            //series.Symbol = UILinePointSymbol.Square;
            //series.SymbolSize = 4;
            //series.SymbolLineWidth = 2;
            //series.SymbolColor = Color.Red;            
                       
            //option.XAxis.Name = "Phase";
            //option.YAxis.Name = "Voltage";
            //option.XAxis.SetRange(0, 127);
            //option.YAxis.SetRange(0, 127);
            //option.Y2Axis.Name = "数值";

            option.YAxisScaleLines.Add(new UIScaleLine() { Color = Color.Red, Name = "上限", Value = 3.5 });
            //option.Y2AxisScaleLines.Add(new UIScaleLine() { Color = Color.Gold, Name = "下限", Value = 12, DashDot = true });

            option.XAxisScaleLines.Add(new UIScaleLine() { Color = Color.Lime, Name = "3", Value = 3 });
            //option.XAxisScaleLines.Add(new UIScaleLine() { Color = Color.Gold, Name = "6", Value = 6 });

            lineChart_EOM.SetOption(option);
            lineChart_EOM.ChartStyleType = UIChartStyleType.Dark;

            UIBarOption option1 = new UIBarOption();
            UILineOption option2 = new UILineOption();
            uiBarChart_DebugDFT.SetOption(option1);
            uiLineChart_DebugDFT.SetOption(option2);
        }

        private void PrintToCSV(int[][] data, string filename)
        {
            
            try
            {
                StreamWriter sw = File.CreateText(filename);
                for (int ix_v = data.Length - 1; ix_v > 0; ix_v--)                
                {
                    for (int ix_p = 0; ix_p < data.Length; ix_p++)
                        sw.Write(data[ix_p][ix_v] + ",");
                    sw.WriteLine();
                }

                sw.Close();
            }
            catch
            {
                MessageBox.Show("Save log file failed!");
            }
            finally
            {
                
            }
        }

        #endregion Funcs


        enum SerDesCH
        {
            CH_A = 0,
            CH_B = 1,
            CH_EW = 2,
            CH_C = 10,
            CH_D = 11,
            CH_NS = 12
        }

        private void cmb_ChannelSel_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch(cmb_ChannelSel.SelectedIndex)
            {
                case 0:
                    cur_ch = SerDesCH.CH_A;
                    break;
                case 1:
                    cur_ch = SerDesCH.CH_B;
                    break; 
                case 2:
                    cur_ch = SerDesCH.CH_C;
                    break;
                case 3:
                    cur_ch = SerDesCH.CH_D;
                    break;
            }
        }

        private void cmb_popThresh_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.esm_pop_thresh = (long)Math.Pow(10, this.cmb_popThresh.SelectedIndex + 1);
        }
        
        private void cmb_UICode_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.UI_CODE =(int)(64 * Math.Pow(2, this.cmb_UICode.SelectedIndex));
        }

        private void btn_StartEOM_Click(object sender, EventArgs e)
        {
            bool ret = false;
            ret = DFEFun();
            if (!ret)
            {
                Console.WriteLine("DFE Read Fialed!");
                UIMessageBox.ShowError("DFE Read Fialed!", true, true);
                return;
            }
            else
                Console.WriteLine("DFE Read Done");

            ret = RXFFEFun();
            if (!ret)
            {
                Console.WriteLine("RX CTLE Read Fialed!");
                UIMessageBox.ShowError("RX CTLE Read Fialed!", true, true);
                return;
            }
            else
                Console.WriteLine("RX CTLE Read Done");

            this.Update();

            ret = EOM_Init(cur_ch);
            if (!ret)
            {
                Console.WriteLine("EOM Init Fialed!");
                UIMessageBox.ShowError("EOM Init Fialed!", true, true);
                return;
            }
            else
                Console.WriteLine("EOM Init Done");

            ret = EOM_Alignment(cur_ch);
            if (!ret)
            {
                Console.WriteLine("EOM_Alignment Fialed!");
                UIMessageBox.ShowError("EOM_Alignment Fialed!", true, true);
                return;
            }
            else
                Console.WriteLine("EOM_Alignment Done");

            for (int ix_repeat = 0; ix_repeat < this.numUD_RepeatCnt.Value; ix_repeat++)
            {
                Console.WriteLine("Repeat eye print:{0}", ix_repeat);
                //ret = EOM_Print(cur_ch);
                ret = EOM_Print_New(cur_ch);
                if (!ret)
                {
                    Console.WriteLine("EOM_Print Fialed!");
                    UIMessageBox.ShowError("EOM_Print Fialed!", true, true);
                    return;
                }
            }

            EOM_Plot_Eye();

            UIMessageBox.ShowSuccess("EOM Sweep Done", true, true);

            ret = EOM_Turn_Off(cur_ch);
            if (!ret)
            {
                Console.WriteLine("Turn off EOM Fialed!");
                return;
            }
            else
                Console.WriteLine("Turn Off EOM Done");

        }

        private void btn_ClearEye_Click(object sender, EventArgs e)
        {
            if (eye_diagram[0] == null)
                return;

            for (int ix = 0; ix < eye_diagram.Length; ix++)
            {                
                Array.Clear(eye_diagram[ix], 0, eye_diagram[ix].Length);
            }
        }

        private void btn_refreshChart_Click(object sender, EventArgs e)
        {
            EOM_EyeChar_Refresh();
        }

        private void uiTrackBar1_ValueChanged(object sender, EventArgs e)
        {
            //this.uiTextBox1.Text = uiTrackBar1.Value.ToString();
            //this.uiTextBox2.Text = "0x" + uiTrackBar1.Value.ToString("X2");
        }

        private void uiButton_DFE_Click(object sender, EventArgs e)
        {
            DFEFun();
        }

        private bool DFEFun()
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (cur_ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            uint tempData = 0;

            UInt32 dfe_lock = 0;
            ret = commDev.IICRead((UInt32)(0x7420 + offset), out dfe_lock, 15, 15);  //reg_rd_dfe_lock;
            if (!ret && dfe_lock != 1)
            {
                uiLedBulb_dfe_lock.Color = Color.Red;
                Console.WriteLine("dfe_lock Read Error");
                return ret;
            }
            else
            {
                uiLedBulb_dfe_lock.Color = Color.PaleGreen;
            }

            ret = commDev.IICRead((UInt32)(0x743C + offset), out tempData, 19, 24);  //reg_rd_sav_f0a[5:0];
            if (ret)
            {
                numericUpDown_sav_f0.Value = tempData;
                tempData = 0;
            }
            else
            {
                Console.WriteLine("sav_f0a Read Error");
                return ret;
            }

            ret = commDev.IICRead((UInt32)(0x743C + offset), out tempData, 1, 6);  //reg_rd_sav_f1[5:0];
            if (ret)
            {
                numericUpDown_sav_f1.Value = tempData;
                tempData = 0;
            }
            else
            {
                Console.WriteLine("sav_f1 Read Error");
                return ret;
            }

            ret = commDev.IICRead((UInt32)(0x7440 + offset), out tempData, 27, 31);  //reg_rd_sav_f1p5[4:0];
            if (ret)
            {
                numericUpDown_sav_f1p5.Value = tempData;
                tempData = 0;
            }
            else
            {
                Console.WriteLine("sav_f1p5 Read Error");
                return ret;
            }

            ret = commDev.IICRead((UInt32)(0x7440 + offset), out tempData, 22, 26);  //reg_rd_sav_f2[4:0];
            if (ret)
            {
                numericUpDown_sav_f2.Value = tempData;
                tempData = 0;
            }
            else
            {
                Console.WriteLine("sav_f2 Read Error");
                return ret;
            }

            ret = commDev.IICRead((UInt32)(0x7440 + offset), out tempData, 18, 21);  //reg_rd_sav_f2p5[3:0];
            if (ret)
            {
                numericUpDown_sav_f2p5.Value = tempData;
                tempData = 0;
            }
            else
            {
                Console.WriteLine("sav_f2p5 Read Error");
                return ret;
            }

            ret = commDev.IICRead((UInt32)(0x7440 + offset), out tempData, 14, 17);  //reg_rd_sav_f3[3:0];
            if (ret)
            {
                numericUpDown_sav_f3.Value = tempData;
                tempData = 0;
            }
            else
            {
                Console.WriteLine("sav_f3 Read Error");
                return ret;
            }

            ret = commDev.IICRead((UInt32)(0x7440 + offset), out tempData, 10, 13);  //reg_rd_sav_f4[3:0];
            if (ret)
            {
                numericUpDown_sav_f4.Value = tempData;
                tempData = 0;
            }
            else
            {
                Console.WriteLine("sav_f4 Read Error");
                return ret;
            }

            ret = commDev.IICRead((UInt32)(0x7440 + offset), out tempData, 6, 9);  //reg_rd_sav_f5[3:0];
            if (ret)
            {
                numericUpDown_sav_f5.Value = tempData;
                tempData = 0;
            }
            else
            {
                Console.WriteLine("sav_f5 Read Error");
                return ret;
            }

            RegChart();
            RegChart1();

            return ret;
        }

        private void RegChart()
        {
            UILineOption option = new UILineOption();
            option.ToolTip.Visible = true;
            option.Title = new UITitle();
            option.Title.Text = "DFE参数值";
            option.Title.SubText = "";

            option.XAxis.Name = "寄存器";
            option.YAxis.Name = "DFE参数值";
            option.XAxis.SetRange(0, 5);
            //option.YAxis.SetRange(-20, 64);

            //坐标轴显示小数位数
            option.XAxis.AxisLabel.DecimalPlaces = 1;

            var series = option.AddSeries(new UILineSeries("Line1"));
            series.Symbol = UILinePointSymbol.Star;
            series.SymbolSize = 4;
            series.SymbolLineWidth = 2;
            series.SymbolColor = Color.Red;
            series.ShowLine = true;
            series.Smooth = true;
            //数据点显示小数位数
            series.YAxisDecimalPlaces = 2;

            int sav_f1p5 = ConvertToSigned((uint)numericUpDown_sav_f1p5.Value, 5);
            int sav_f2 = ConvertToSigned((uint)numericUpDown_sav_f2.Value, 5);
            int sav_f2p5 = ConvertToSigned((uint)numericUpDown_sav_f2p5.Value, 4);
            int sav_f3 = ConvertToSigned((uint)numericUpDown_sav_f3.Value, 4);
            int sav_f4 = ConvertToSigned((uint)numericUpDown_sav_f4.Value, 4);
            int sav_f5 = ConvertToSigned((uint)numericUpDown_sav_f5.Value, 4);

            series.Add(0, (double)numericUpDown_sav_f0.Value);
            series.Add(1, (double)numericUpDown_sav_f1.Value);
            //series.Add(1.5, (double)sav_f1p5);
            series.Add(2, (double)sav_f2);
            //series.Add(2.5, (double)sav_f2p5);
            series.Add(3, (double)sav_f3);
            series.Add(4, (double)sav_f4);
            series.Add(5, (double)sav_f5);
            
            uiLineChart_DebugDFT.SetOption(option);
            Console.WriteLine("DFT LineChart");
        }

        private void RegChart1()
        {
            UIBarOption option = new UIBarOption();
            option.ToolTip.Visible = true;
            option.Title = new UITitle();
            option.Title.Text = "DFE参数值";
            option.Title.SubText = "";

            //设置Legend
            option.Legend = new UILegend();
            option.Legend.Orient = UIOrient.Horizontal;
            option.Legend.Top = UITopAlignment.Top;
            option.Legend.Left = UILeftAlignment.Left;
            option.Legend.AddData("Bar1");

            //option.XAxis.SetRange(0, 9);
            option.YAxis.SetRange(-20, 70);

            int sav_f1p5 = ConvertToSigned((uint)numericUpDown_sav_f1p5.Value, 5);
            int sav_f2 = ConvertToSigned((uint)numericUpDown_sav_f2.Value, 5);
            int sav_f2p5 = ConvertToSigned((uint)numericUpDown_sav_f2p5.Value, 4);
            int sav_f3 = ConvertToSigned((uint)numericUpDown_sav_f3.Value, 4);
            int sav_f4 = ConvertToSigned((uint)numericUpDown_sav_f4.Value, 4);
            int sav_f5 = ConvertToSigned((uint)numericUpDown_sav_f5.Value, 4); 

            var series = new UIBarSeries();
            series.Name = "Bar1";
            series.AddData((double)numericUpDown_sav_f0.Value, Color.FromArgb(43, 71, 85));
            series.AddData((double)numericUpDown_sav_f1.Value, Color.FromArgb(43, 71, 85));
            //series.AddData(sav_f1p5, Color.FromArgb(43, 71, 85));
            series.AddData(sav_f2, Color.FromArgb(43, 71, 85));
            //series.AddData(sav_f2p5, Color.FromArgb(43, 71, 85));
            series.AddData(sav_f3, Color.FromArgb(43, 71, 85));
            series.AddData(sav_f4, Color.FromArgb(43, 71, 85));
            series.AddData(sav_f5, Color.FromArgb(43, 71, 85));

            //数据显示小数位数
            series.DecimalPlaces = 1;
            option.Series.Add(series);

            option.XAxis.Data.Add("sav_f0a[5:0]");
            option.XAxis.Data.Add("sav_f1[5:0]");
            //option.XAxis.Data.Add("sav_f1p5[4:0]");
            option.XAxis.Data.Add("sav_f2[4:0]");
            //option.XAxis.Data.Add("sav_f2p5[3:0]");
            option.XAxis.Data.Add("sav_f3[3:0]");
            option.XAxis.Data.Add("sav_f4[3:0]");
            option.XAxis.Data.Add("sav_f5[3:0]");

            option.YAxis.Scale = true;
            option.XAxis.Name = "寄存器";
            option.YAxis.Name = "DFE参数值";
            //option.XAxis.AxisLabel.Angle = 60;//(0° ~ 90°)
            //坐标轴显示小数位数
            option.YAxis.AxisLabel.DecimalPlaces = 1;
            option.ToolTip.AxisPointer.Type = UIAxisPointerType.Shadow;
            option.ShowValue = true;

            //uiBarChart_DebugDFT.ChartStyleType = UIChartStyleType.Dark;

            uiBarChart_DebugDFT.SetOption(option);
            Console.WriteLine("DFT BarChart");
        }

        private int ConvertToSigned(uint tempData, int bits)
        {
            int tempData1 = (int)tempData;
            // 如果最高位是1，则它是一个负数  
            if ((tempData1 & (1 << (bits - 1))) != 0) // 检查最高位（符号位）  
            {
               //将最高位取反
                tempData1 = -(tempData1 ^ (1 << (bits - 1)));
            }
            return tempData1;
        }

        private void uiImageButton_ChangeLineBar_Click(object sender, EventArgs e)
        {
            if (uiBarChart_DebugDFT.Visible == true)
            {
                uiLineChart_DebugDFT.Visible = true;
                uiBarChart_DebugDFT.Visible = false;
            }
            else if (uiLineChart_DebugDFT.Visible)
            {
                uiLineChart_DebugDFT.Visible = false;
                uiBarChart_DebugDFT.Visible = true;
            }
        }

        private void uiButton_RXFFE_Click(object sender, EventArgs e)
        {
            RXFFEFun();
        }

        private bool RXFFEFun()
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (cur_ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            uint tempData = 0;

            UInt32 trx_train_done_int = 0;
            ret = commDev.IICRead((UInt32)(0x744C + offset), out trx_train_done_int, 1, 1);  //reg_rd_trx_train_done_int;
            if (!ret && trx_train_done_int != 1)
            {
                uiLedBulb_trx_train_done_int.Color = Color.Red;
                Console.WriteLine("trx_train_done_int Read Error");
                return ret;
            }
            else
            {
                uiLedBulb_trx_train_done_int.Color = Color.PaleGreen;
            }

            UInt32 adapted_ffe_cap = 0;
            ret = commDev.IICRead((UInt32)(0x7418 + offset), out adapted_ffe_cap, 24, 27);  //reg_rd_adapted_ffe_cap[3:0];
            if (ret)
            {
                numericUpDown_adapted_ffe_cap.Value = adapted_ffe_cap;
                switch (adapted_ffe_cap)
                {
                    case 0:
                        {
                            ret = commDev.IICRead((UInt32)(0x7494 + offset), out tempData, 7, 9);  //reg_rd_ffe_cap_sel0[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel0[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 29, 31);  //reg_rd_ffe_cap_sel20[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel20[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 1:
                        {
                            ret = commDev.IICRead((UInt32)(0x7494 + offset), out tempData, 4, 6);  //reg_rd_ffe_cap_sel1[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel1[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 26, 28);  //reg_rd_ffe_cap_sel21[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel21[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 2:
                        {
                            ret = commDev.IICRead((UInt32)(0x7494 + offset), out tempData, 1, 3);  //reg_rd_ffe_cap_sel2[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel2[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 23, 25);  //reg_rd_ffe_cap_sel22[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel22[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 3:
                        {
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 11, 13);  //reg_rd_ffe_cap_sel3[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel3[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 20, 22);  //reg_rd_ffe_cap_sel23[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel23[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 4:
                        {
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 8, 10);  //reg_rd_ffe_cap_sel4[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel4[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 17, 19);  //reg_rd_ffe_cap_sel24[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel24[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 5:
                        {
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 5, 7);  //reg_rd_ffe_cap_sel5[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel5[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 14, 16);  //reg_rd_ffe_cap_sel25[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel25[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 6:
                        {
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 2, 4);  //reg_rd_ffe_cap_sel6[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel6[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 11, 13);  //reg_rd_ffe_cap_sel26[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel26[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 7:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A0 + offset), out tempData, 29, 31);  //reg_rd_ffe_cap_sel7[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel7[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 8, 10);  //reg_rd_ffe_cap_sel27[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel27[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 8:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A0 + offset), out tempData, 26, 28);  //reg_rd_ffe_cap_sel8[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel8[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 5, 7);  //reg_rd_ffe_cap_sel28[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel28[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 9:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A0 + offset), out tempData, 23, 25);  //reg_rd_ffe_cap_sel9[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel9[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x7498 + offset), out tempData, 2, 4);  //reg_rd_ffe_cap_sel29[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel29[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 0xa:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A4 + offset), out tempData, 17, 19);  //reg_rd_ffe_cap_sela[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sela[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 29, 31);  //reg_rd_ffe_cap_sel2a[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel2a[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 0xb:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A4 + offset), out tempData, 14, 16);  //reg_rd_ffe_cap_selb[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_selb[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 26, 28);  //reg_rd_ffe_cap_sel2b[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel2b[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 0xc:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A4 + offset), out tempData, 11, 13);  //reg_rd_ffe_cap_selc[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_selc[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 23, 25);  //reg_rd_ffe_cap_sel2c[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel2c[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 0xd:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A4 + offset), out tempData, 8, 10);  //reg_rd_ffe_cap_seld[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_seld[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 20, 22);  //reg_rd_ffe_cap_sel2d[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel2d[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 0xe:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A4 + offset), out tempData, 5, 7);  //reg_rd_ffe_cap_sele[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sele[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 17, 19);  //reg_rd_ffe_cap_sel2e[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel2e[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    case 0xf:
                        {
                            ret = commDev.IICRead((UInt32)(0x74A4 + offset), out tempData, 2, 4);  //reg_rd_ffe_cap_self[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_self[2:0] Read Error");
                                return ret;
                            }
                            ret = commDev.IICRead((UInt32)(0x749C + offset), out tempData, 14, 16);  //reg_rd_ffe_cap_sel2f[2:0];
                            if (ret)
                                numericUpDown_ffe_cap_sel_2x.Value = tempData;
                            else
                            {
                                Console.WriteLine("ffe_cap_sel2f[2:0] Read Error");
                                return ret;
                            }
                        }
                        break;
                    default:
                        Console.WriteLine("adapted_ffe_cap[3:0] 值不为0~15");
                        break;
                }
            }
            else
            {
                Console.WriteLine("adapted_ffe_cap[3:0] Read Error");
                return ret;
            }

            return ret;
        }

        private void uiButton_TXFFE_Click(object sender, EventArgs e)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (cur_ch < SerDesCH.CH_EW) ? 0 : 0x1000;

            uint tempData = 0;

            UInt32 link_train_cs = 0;
            ret = commDev.IICRead((UInt32)(0x6534 + 0), out link_train_cs, 7, 11);  //reg_rd_link_train_cs[4:0];
            if (!ret && link_train_cs != 7)
            {
                uiLedBulb_link_train_cs.Color = Color.Red;
                Console.WriteLine("link_train_cs Read Error");
                return;
            }
            else
            {
                uiLedBulb_link_train_cs.Color = Color.PaleGreen;
            }

            UInt32 sdtrain_bcpcs_local_recomend_preset = 0;
            ret = commDev.IICRead((UInt32)(0x6534 + 0), out sdtrain_bcpcs_local_recomend_preset, 20, 23);  //reg_rd_sdtrain_bcpcs_local_recomend_preset[3:0];
            if (ret)
            {
                numericUpDown_sdtrain.Value = sdtrain_bcpcs_local_recomend_preset;
                switch (sdtrain_bcpcs_local_recomend_preset)
                {
                    case 0:
                        {
                            if(tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x72DC + offset), out tempData, 0, 3);  //reg_rd_tx_emph0_default0_g0[3:0];
                                if (ret)
                                    numericUpDown_TxEmph0.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph0_default0_g0[3:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x72DC + offset), out tempData, 8, 13);  //reg_rd_tx_amp_default0_g0[5:0];
                                if (ret)
                                    numericUpDown_TxAmp.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_amp_default0_g0[5:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x72DC + offset), out tempData, 4, 7);  //reg_rd_tx_emph1_default0_g0[3:0];
                                if (ret)
                                    numericUpDown_TxEmph1.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph1_default0_g0[3:0] Read Error");
                                    return;
                                }
                            }
                            else if(tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x74D0 + offset), out tempData, 2, 5);  //reg_rd_tx_emph0_default0_g1[3:0];
                                if (ret)
                                    numericUpDown_TxEmph0.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph0_default0_g1[3:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x74D0 + offset), out tempData, 10, 15);  //reg_rd_tx_amp_default0_g1[5:0];
                                if (ret)
                                    numericUpDown_TxAmp.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_amp_default0_g1[5:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x74D0 + offset), out tempData, 6, 9);  //reg_rd_tx_emph1_default0_g1[3:0];
                                if (ret)
                                    numericUpDown_TxEmph1.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph1_default0_g1[3:0] Read Error");
                                    return;
                                }
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x7580 + offset), out tempData, 2, 5);  //reg_rd_tx_emph0_default0_g2[3:0];
                                if (ret)
                                    numericUpDown_TxEmph0.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph0_default0_g2[3:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x7580 + offset), out tempData, 10, 15);  //reg_rd_tx_amp_default0_g2[5:0];
                                if (ret)
                                    numericUpDown_TxAmp.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_amp_default0_g2[5:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x7580 + offset), out tempData, 6, 9);  //reg_rd_tx_emph1_default0_g2[3:0];
                                if (ret)
                                    numericUpDown_TxEmph1.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph1_default0_g2[3:0] Read Error");
                                    return;
                                }
                            }
                        }
                        break;
                    case 1:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x72E0 + offset), out tempData, 2, 5);  //reg_rd_tx_emph0_default1_g0[3:0];
                                if (ret)
                                    numericUpDown_TxEmph0.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph0_default1_g0[3:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x72E0 + offset), out tempData, 10, 15);  //reg_rd_tx_amp_default1_g0[5:0];
                                if (ret)
                                    numericUpDown_TxAmp.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_amp_default1_g0[5:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x72E0 + offset), out tempData, 6, 9);  //reg_rd_tx_emph1_default1_g0[3:0];
                                if (ret)
                                    numericUpDown_TxEmph1.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph1_default1_g0[3:0] Read Error");
                                    return;
                                }
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x74D4 + offset), out tempData, 2, 5);  //reg_rd_tx_emph0_default1_g1[3:0];
                                if (ret)
                                    numericUpDown_TxEmph0.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph0_default1_g1[3:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x74D4 + offset), out tempData, 10, 15);  //reg_rd_tx_amp_default1_g1[5:0];
                                if (ret)
                                    numericUpDown_TxAmp.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_amp_default1_g1[5:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x74D4 + offset), out tempData, 6, 9);  //reg_rd_tx_emph1_default1_g1[3:0];
                                if (ret)
                                    numericUpDown_TxEmph1.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph1_default1_g1[3:0] Read Error");
                                    return;
                                }
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x7584 + offset), out tempData, 2, 5);  //reg_rd_tx_emph0_default1_g2[3:0];
                                if (ret)
                                    numericUpDown_TxEmph0.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph0_default1_g2[3:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x7584 + offset), out tempData, 10, 15);  //reg_rd_tx_amp_default1_g2[5:0];
                                if (ret)
                                    numericUpDown_TxAmp.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_amp_default1_g2[5:0] Read Error");
                                    return;
                                }
                                ret = commDev.IICRead(txDevAddr, (UInt32)(0x7584 + offset), out tempData, 6, 9);  //reg_rd_tx_emph1_default1_g2[3:0];
                                if (ret)
                                    numericUpDown_TxEmph1.Value = tempData;
                                else
                                {
                                    Console.WriteLine("tx_emph1_default1_g2[3:0] Read Error");
                                    return;
                                }
                            }
                        }
                        break;
                    case 2:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x7338, 2, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74D8, 2, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x7588, 2, 2);
                            }
                        }
                        break;
                    case 3:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x733C, 3, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74DC, 3, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x758C, 3, 2);
                            }
                        }
                        break;
                    case 4:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x737C, 4, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74E0, 4, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x7590, 4, 2);
                            }
                        }
                        break;
                    case 5:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x73DC, 5, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74E4, 5, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x7594, 5, 2);
                            }
                        }
                        break;
                    case 6:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x73F4, 6, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74E8, 6, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x7598, 6, 2);
                            }
                        }
                        break;
                    case 7:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x73F8, 7, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74EC, 7, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x759C, 7, 2);
                            }
                        }
                        break;
                    case 8:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x74B0, 8, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74F0, 8, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x75A0, 8, 2);
                            }
                        }
                        break;
                    case 9:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x74B4, 9, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74F4, 9, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x75A4, 9, 2);
                            }
                        }
                        break;
                    case 10:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x74B8, 10, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74F8, 10, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x75A8, 10, 2);
                            }
                        }
                        break;
                    case 11:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x74BC, 11, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x74FC, 11, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x75AC, 11, 2);
                            }
                        }
                        break;
                    case 12:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x74C0, 12, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x7500, 12, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x75B0, 12, 2);
                            }
                        }
                        break;
                    case 13:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x74C4, 13, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x7504, 13, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x75B4, 13, 2);
                            }
                        }
                        break;
                    case 14:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x74C8, 14, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x7508, 14, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x75B8, 14, 2);
                            }
                        }
                        break;
                    case 15:
                        {
                            if (tx_speed == TXSpeed.TX_2G || tx_speed == TXSpeed.TX_3p2G || tx_speed == TXSpeed.TX_4G)
                            {
                                TxAbridgeRead(0x74CC, 15, 0);
                            }
                            else if (tx_speed == TXSpeed.TX_6p4G || tx_speed == TXSpeed.TX_8G)
                            {
                                TxAbridgeRead(0x750C, 15, 1);
                            }
                            else if (tx_speed == TXSpeed.TX_12p8G)
                            {
                                TxAbridgeRead(0x75BC, 15, 2);
                            }
                        }
                        break;
                }
            }
            else
            {
                Console.WriteLine("sdtrain_bcpcs_local_recomend_preset[3:0] Read Error");
            }

            TXEMPH01AMP();
        }

        enum TXSpeed
        {
            TX_2G = 0,
            TX_3p2G = 1,
            TX_4G = 2,
            TX_6p4G = 3,
            TX_8G = 4,
            TX_12p8G = 5
        }

        private void comboBox_TxSpeed_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (comboBox_TxSpeed.SelectedIndex)
            {
                case 0:
                    tx_speed = TXSpeed.TX_2G;
                    break;
                case 1:
                    tx_speed = TXSpeed.TX_3p2G;
                    break;
                case 2:
                    tx_speed = TXSpeed.TX_4G;
                    break;
                case 3:
                    tx_speed = TXSpeed.TX_6p4G;
                    break;
                case 4:
                    tx_speed = TXSpeed.TX_8G;
                    break;
                case 5:
                    tx_speed = TXSpeed.TX_12p8G;
                    break;
            }
        }

        private void TxAbridgeRead(UInt32 addr, int defaultIndex, int gIndex)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (cur_ch < SerDesCH.CH_EW) ? 0 : 0x1000;
            uint tempData = 0;

            ret = commDev.IICRead(txDevAddr, (UInt32)(addr + offset), out tempData, 2, 5);  //reg_rd_tx_emph0_defaultX_gY[3:0];
            if (ret)
                numericUpDown_TxEmph0.Value = tempData;
            else
            {
                Console.WriteLine("tx_emph0_default{0}_g{1}[3:0] Read Error", defaultIndex, gIndex);
                return;
            }
            ret = commDev.IICRead(txDevAddr, (UInt32)(addr + offset), out tempData, 10, 15);  //reg_rd_tx_amp_defaultX_gY[5:0];
            if (ret)
                numericUpDown_TxAmp.Value = tempData;
            else
            {
                Console.WriteLine("tx_amp_default{0}_g{1}[5:0] Read Error", defaultIndex, gIndex);
                return;
            }
            ret = commDev.IICRead(txDevAddr, (UInt32)(addr + offset), out tempData, 6, 9);  //reg_rd_tx_emph1_defaultX_gY[3:0];
            if (ret)
                numericUpDown_TxEmph1.Value = tempData;
            else
            {
                Console.WriteLine("tx_emph1_default{0}_g{1}[3:0] Read Error", defaultIndex, gIndex);
                return;
            }
        }

        private void TXEMPH01AMP()
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (cur_ch < SerDesCH.CH_EW) ? 0 : 0x1000;
            uint tempData = 0;

            ret = commDev.IICRead(txDevAddr, (UInt32)(0x7178 + offset), out tempData, 0, 3);  //reg_rd_TX_EMPH0[3:0];
            if (ret)
            {
                numericUpDown_TX_EMPH0.Value = tempData;
                uiTextBox_TX_EMPH0.Text = (tempData * 30).ToString() + "mV";
            } 
            else
            {
                Console.WriteLine("TX_EMPH0[3:0] Read Error");
                return;
            }
            ret = commDev.IICRead(txDevAddr, (UInt32)(0x7178 + offset), out tempData, 4, 7);  //reg_rd_TX_EMPH1[3:0];
            if (ret)
            {
                numericUpDown_TX_EMPH1.Value = tempData;
                uiTextBox_TX_EMPH1.Text = (tempData * 30).ToString() + "mV";
            } 
            else
            {
                Console.WriteLine("TX_EMPH1[3:0] Read Error");
                return;
            }
            ret = commDev.IICRead(txDevAddr, (UInt32)(0x7178 + offset), out tempData, 9, 13);  //reg_rd_TX_AMP[4:0];
            if (ret)
            {
                numericUpDown_TX_AMP.Value = tempData;
                uiTextBox_TX_AMP.Text = (360 + (tempData * 30)).ToString() + "mV";
            }
            else
            {
                Console.WriteLine("TX_AMP[4:0] Read Error");
                return;
            }
        }

        private void comboBox_TxDevAddr_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (comboBox_TxDevAddr.SelectedIndex)
            {
                case 0:
                    txDevAddr = 0x40;
                    break;
                case 1:
                    txDevAddr = 0x42;
                    break;
            }
        }
    }
}
